#include <QtWidgets>

#include "window.h"
#include <QtWebEngineWidgets/QWebEngineView>

enum { absoluteFileNameRole = Qt::UserRole + 1 };

static inline QString fileNameOfItem(const QTableWidgetItem *item)
{
    return item->data(absoluteFileNameRole).toString();
}

void Window::openFile(const QString &fileName)
{
    QString data;
    QFile file;
    file.setFileName(fileName);
    file.open(QIODevice::ReadOnly | QIODevice::Text);
    data = file.readAll();
    QJsonDocument jsonDoc = QJsonDocument::fromJson(data.toUtf8());
    data = data.replace("\\t","");
    data = data.replace("\"","\\\"");
    data = data.remove(QRegExp("[\\n\\t\\r]"));
    file.close();
    QJsonDocument sd = QJsonDocument::fromJson(data.toUtf8());
    QString s = QString::fromLatin1("displayData('");
    s.append(data).append( QString::fromLatin1("')"));
    webEngineView->page()->runJavaScript(s);
    //QDesktopServices::openUrl(QUrl::fromLocalFile(fileName));
    {
        QJsonObject sett2 = jsonDoc.object();
        QJsonValue uuid = sett2.value(QString("uuid"));
        QStringList path = fileName.split("/");
        QString aaLogDir = "";
        for (int i = 0; i < path.size()-1; i++) {
            if (i == path.size()-3) {
                qInfo(path[i].toStdString().c_str());
                aaLogDir.append("aa_log");
            } else {
                aaLogDir.append(path[i]);
            }
            aaLogDir.append("/");
        }
        qInfo("Going to find the AA data for uuid : %s in folder: %s", uuid.toString().toStdString().c_str(), aaLogDir.toStdString().c_str());
        QStringList filter;/*
        if (!fileName.isEmpty())
            filter << fileName;*/
        QDirIterator it(aaLogDir, filter, QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
        QStringList files;
        while (it.hasNext())
        {
            files << it.next();
        }
        for (int i = 0; i < files.size(); i++){
            if (files[i].contains(uuid.toString(), Qt::CaseInsensitive)){
                QFile file;
                file.setFileName(files[i]);
                file.open(QIODevice::ReadOnly | QIODevice::Text);
                data = file.readAll();
                QJsonDocument jsonDoc = QJsonDocument::fromJson(data.toUtf8());
                data = data.replace("\"","\\\"");
                data = data.remove(QRegExp("[\\n\\t\\r]"));
                file.close();
                QJsonDocument sd = QJsonDocument::fromJson(data.toUtf8());
                QString s = QString::fromLatin1("drawSFRCurve2('");
                s.append(data).append( QString::fromLatin1("')"));
                webEngineView->page()->runJavaScript(s);
            }
        }
        files.sort();
    }
}

Window::Window(QWidget *parent)
    : QWidget(parent)
{
    setWindowTitle(tr("Silicool Data Visualization"));
    QPushButton *browseButton = new QPushButton(tr("&Browse..."), this);
    connect(browseButton, &QAbstractButton::clicked, this, &Window::browse);
    findButton = new QPushButton(tr("&Find"), this);
    connect(findButton, &QAbstractButton::clicked, this, &Window::find);

    fileComboBox = createComboBox(tr("*.json"));
    connect(fileComboBox->lineEdit(), &QLineEdit::returnPressed,
            this, &Window::animateFindClick);
    textComboBox = createComboBox();
    connect(textComboBox->lineEdit(), &QLineEdit::returnPressed,
            this, &Window::animateFindClick);
    //directoryComboBox = createComboBox(QDir::toNativeSeparators(QDir::currentPath()));
    directoryComboBox = createComboBox("");
    connect(directoryComboBox->lineEdit(), &QLineEdit::returnPressed,
            this, &Window::animateFindClick);

    filesFoundLabel = new QLabel;

    //Time Filter Widget
    dt_start = new QDateTimeEdit;
    dt_start->setDate(QDate::currentDate());
    dt_end = new QDateTimeEdit;
    dt_end->setDate(QDate::currentDate());
    dt_end->setTime(QTime::currentTime());

    //Check Box Widget
    timeFilterCheckBox = new QCheckBox;
    timeFilterCheckBox->setText("Apply time filter");
    maunalTestFilterCheckBox = new QCheckBox;
    maunalTestFilterCheckBox->setText("Manual test filter");

    createFilesTable();

    QGridLayout *mainLayout = new QGridLayout(this);
    mainLayout->setColumnMinimumWidth(3, 1200);
    mainLayout->addWidget(new QLabel(tr("Named:")), 0, 0);
    mainLayout->addWidget(fileComboBox, 0, 1, 1, 2);
    mainLayout->addWidget(new QLabel(tr("Keyword:")), 1, 0);
    mainLayout->addWidget(textComboBox, 1, 1, 1, 2);

    mainLayout->addWidget(new QLabel(tr("Date filter:")), 2, 0);
    mainLayout->addWidget(dt_start, 2, 1, 1, 1);
    mainLayout->addWidget(dt_end, 2, 2, 1, 1);

    mainLayout->addWidget(new QLabel(tr("In directory:")), 3, 0);
    mainLayout->addWidget(directoryComboBox, 3, 1);
    mainLayout->addWidget(browseButton, 3, 2);
    mainLayout->addWidget(filesTable, 4, 0, 1, 3);

    mainLayout->addWidget(timeFilterCheckBox, 5, 0);
    mainLayout->addWidget(maunalTestFilterCheckBox, 5, 1);

    mainLayout->addWidget(filesFoundLabel, 6, 0, 1, 2);
    mainLayout->addWidget(findButton, 6, 2);

    //QWidget *webContentsWidget;
    webEngineView = new QWebEngineView();
    webEngineView->setObjectName(QString::fromUtf8("webEngineView"));
    QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Preferred);
    sizePolicy1.setHorizontalStretch(0);
    sizePolicy1.setVerticalStretch(0);
    sizePolicy1.setHeightForWidth(webEngineView->sizePolicy().hasHeightForWidth());
    webEngineView->setSizePolicy(sizePolicy1);
    webEngineView->setProperty("url", QVariant(QUrl(QString::fromUtf8("about:blank"))));
    mainLayout->addWidget(webEngineView, 0, 3, 5, 3);

    qInfo(QDir::currentPath().toStdString().c_str());

    QString unitReportPath = QDir::currentPath().append("/flowchart/unitReport.html");
    qInfo(unitReportPath.toStdString().c_str());
    webEngineView->load(QUrl(unitReportPath));

    connect(new QShortcut(QKeySequence::Quit, this), &QShortcut::activated,
            qApp, &QApplication::quit);


    directoryComboBox->setEditText(QDir::currentPath());
}

void Window::browse()
{
    QString directory =
            QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Find Files"), QDir::currentPath()));

    if (!directory.isEmpty()) {
        if (directoryComboBox->findText(directory) == -1)
            directoryComboBox->addItem(directory);
        directoryComboBox->setCurrentIndex(directoryComboBox->findText(directory));
    }
}

static void updateComboBox(QComboBox *comboBox)
{
    if (comboBox->findText(comboBox->currentText()) == -1)
        comboBox->addItem(comboBox->currentText());
}

void Window::find()
{
    filesTable->setRowCount(0);

    QString fileName = fileComboBox->currentText();
    QString text = textComboBox->currentText();
    QString path = QDir::cleanPath(directoryComboBox->currentText());
    currentDir = QDir(path);

    updateComboBox(fileComboBox);
    updateComboBox(textComboBox);
    updateComboBox(directoryComboBox);

    QStringList filter;
    if (!fileName.isEmpty())
        filter << fileName;
    QDirIterator it(path, filter, QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
    QStringList files;
    while (it.hasNext())
        files << it.next();
    if (!text.isEmpty())
        files = findFiles(files, text);
    files.sort();
    showFiles(files);
}

void Window::animateFindClick()
{
    findButton->animateClick();
}

void Window::exportData(const QStringList &files)
{

    bool ok;
    QString csvFilename = QInputDialog::getText(this, tr("Silicool Export Data"),
                                         tr("Filename:"), QLineEdit::Normal,
                                         QDir::home().dirName(), &ok);
    if (!ok || csvFilename.isEmpty()) return;

    csvFilename.append(".csv");

    QProgressDialog progressDialog(this);
    progressDialog.setCancelButtonText(tr("&Cancel"));
    progressDialog.setRange(0, files.size());
    progressDialog.setWindowTitle(tr("Exporting Data"));

    QString file_name = "csvFilename";
    QFile csvFile(csvFilename);
    csvFile.open(QIODevice::WriteOnly | QIODevice::Text | QFile::Truncate);
    int prevEntryCount = 0;
    for (int i = 0; i < files.size(); ++i) {
        progressDialog.setValue(i);
        progressDialog.setLabelText(tr("Exporting data from file number %1 of %n...\n%2", nullptr, files.size()).arg(i).arg(files[i]));
        QCoreApplication::processEvents();
        if (progressDialog.wasCanceled())
            break;
        QFile file;
        file.setFileName(files[i]);
        file.open(QIODevice::ReadOnly | QIODevice::Text);
        QString data = file.readAll();
        QJsonDocument jsonDoc = QJsonDocument::fromJson(data.toUtf8());
        QString line1 = "";
        QString line2 = "";
        int currEntryCount = 0;
        foreach(const QString& key, jsonDoc.object().keys()) {
            QJsonObject obj = jsonDoc.object()[key].toObject();
            if (!key.compare("uuid") || !key.compare("lotNumber")) {
                line1.append(key).append(",");
                line2.append(jsonDoc.object()[key].toString()).append(",");
            }
            foreach(const QString& k, obj.keys()){
                QString value = obj[k].toString();
                currEntryCount++;
                if (value.isEmpty()) {
                    line2.append(QString::number(obj[k].toDouble())).append(",");
                } else {
                    line2.append(value).append(",");
                }
                line1.append(key).append(".").append(k).append(",");
            }
        }
        line1.append("\n");
        line2.append("\n");
        if (currEntryCount != prevEntryCount)
            csvFile.write(line1.toStdString().c_str());
        prevEntryCount = currEntryCount;
        csvFile.write(line2.toStdString().c_str());
        file.close();
        QThread::msleep(10);
    }
    QDesktopServices::openUrl(QDir::currentPath());
}

QStringList Window::findFiles(const QStringList &files, const QString &text)
{
    QProgressDialog progressDialog(this);
    progressDialog.setCancelButtonText(tr("&Cancel"));
    progressDialog.setRange(0, files.size());
    progressDialog.setWindowTitle(tr("Find Files"));

    QMimeDatabase mimeDatabase;
    QStringList foundFiles;

    for (int i = 0; i < files.size(); ++i) {
        progressDialog.setValue(i);
        progressDialog.setLabelText(tr("Searching file number %1 of %n...", nullptr, files.size()).arg(i));
        QCoreApplication::processEvents();
        //! [6]

        if (progressDialog.wasCanceled())
            break;

        //! [7]
        const QString fileName = files.at(i);
        const QMimeType mimeType = mimeDatabase.mimeTypeForFile(fileName);
        if (mimeType.isValid() && !mimeType.inherits(QStringLiteral("text/plain"))) {
            qWarning() << "Not searching binary file " << QDir::toNativeSeparators(fileName);
            continue;
        }
        QFile file(fileName);
        if (file.open(QIODevice::ReadOnly)) {
            QString line;
            QTextStream in(&file);
            while (!in.atEnd()) {
                if (progressDialog.wasCanceled())
                    break;
                line = in.readLine();
                if (line.contains(text, Qt::CaseInsensitive)) {
                    foundFiles << files[i];
                    break;
                }
            }
        }
    }
    return foundFiles;
}

void Window::showFiles(const QStringList &paths)
{
    QProgressDialog progressDialog(this);
    progressDialog.setCancelButtonText(tr("&Cancel"));
    progressDialog.setRange(0, paths.size());
    progressDialog.setWindowTitle(tr("Data Indexing"));
    int i = 0;
    for (const QString &filePath : paths) {
        if (progressDialog.wasCanceled())
            break;
        progressDialog.setValue(i);
        progressDialog.setLabelText(tr("Searching file number %1 of %n...", nullptr, paths.size()).arg(i));
        i++;
        QFile file(filePath);
        bool detectFail = false;
        if (file.open(QIODevice::ReadOnly)) {
            QString line;
            QTextStream in(&file);
            while (!in.atEnd()) {
                line = in.readLine();
                if (line.contains("fail", Qt::CaseInsensitive)) {
                    detectFail = true;
                    break;
                }
            }
        }

        const QString toolTip = QDir::toNativeSeparators(filePath);
        const QString relativePath = QDir::toNativeSeparators(currentDir.relativeFilePath(filePath));
        const qint64 size = QFileInfo(filePath).size();
        const QDateTime fileDate = QFileInfo(filePath).lastModified();

        if (this->timeFilterCheckBox->isChecked()){
            QDateTime start_time = dt_start->dateTime();
            QDateTime stop_time = dt_end->dateTime();
            if (fileDate >= start_time && fileDate <= stop_time){
                qInfo("OK");
            } else {
                qInfo("Time filter out");
                continue;
            }
        }

        QTableWidgetItem *fileNameItem = new QTableWidgetItem(relativePath);
        fileNameItem->setData(absoluteFileNameRole, QVariant(filePath));
        fileNameItem->setToolTip(toolTip);
        fileNameItem->setFlags(fileNameItem->flags() ^ Qt::ItemIsEditable);
        QTableWidgetItem *sizeItem = new QTableWidgetItem(QLocale().formattedDataSize(size));
        sizeItem->setData(absoluteFileNameRole, QVariant(filePath));
        sizeItem->setToolTip(toolTip);
        sizeItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
        sizeItem->setFlags(sizeItem->flags() ^ Qt::ItemIsEditable);
        QTableWidgetItem *fileTimeItem = new QTableWidgetItem(fileDate.toString("MM-dd hh:mm:ss"));
        fileTimeItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
        fileTimeItem->setFlags(sizeItem->flags() ^ Qt::ItemIsEditable);
        QString result = detectFail ? "Fail" : "Pass";
        QTableWidgetItem *resultItem = new QTableWidgetItem(result);
        resultItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
        resultItem->setFlags(sizeItem->flags() ^ Qt::ItemIsEditable);

        int row = filesTable->rowCount();
        filesTable->insertRow(row);
        filesTable->setItem(row, 0, fileNameItem);
        filesTable->setItem(row, 1, sizeItem);
        QString time = fileDate.toString("hh:mm:ss");
        filesTable->setItem(row, 2, fileTimeItem);
        filesTable->setItem(row, 3, resultItem);
    }
    filesFoundLabel->setText(tr("%n file(s) found (Double click on a file to open it)", nullptr, paths.size()));
    filesFoundLabel->setWordWrap(true);
}

QComboBox *Window::createComboBox(const QString &text)
{
    QComboBox *comboBox = new QComboBox;
    comboBox->setEditable(true);
    comboBox->addItem(text);
    comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    return comboBox;
}

void Window::createFilesTable()
{
    filesTable = new QTableWidget(0, 4);
    filesTable->setSelectionBehavior(QAbstractItemView::SelectRows);

    QStringList labels;
    labels << tr("Filename") << tr("Size") << tr("Time") << tr("Result");
    filesTable->setColumnWidth(1, 50);
    filesTable->setColumnWidth(2, 100);
    filesTable->setColumnWidth(3, 60);
    filesTable->setHorizontalHeaderLabels(labels);
    filesTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
    filesTable->verticalHeader()->hide();
    filesTable->setShowGrid(false);
    filesTable->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(filesTable, &QTableWidget::customContextMenuRequested,
            this, &Window::contextMenu);
    connect(filesTable, &QTableWidget::cellActivated,
            this, &Window::openFileOfItem);
}

void Window::openFileOfItem(int row, int /* column */)
{
    const QTableWidgetItem *item = filesTable->item(row, 0);
    openFile(fileNameOfItem(item));
}

void Window::contextMenu(const QPoint &pos)
{
    const QTableWidgetItem *item = filesTable->itemAt(pos);
    if (!item)
        return;
    QMenu menu;
#ifndef QT_NO_CLIPBOARD
    QAction *copyAction = menu.addAction("Copy Name");
#endif
    QAction *openAction = menu.addAction("Open");
    QAction *exportAction = menu.addAction("Export");
    QAction *action = menu.exec(filesTable->mapToGlobal(pos));
    if (!action)
        return;
    const QString fileName = fileNameOfItem(item);
    if (action == openAction){
        openFile(fileName);
    } else if (action == exportAction){
        QModelIndexList selection = filesTable->selectionModel()->selectedRows();
        QStringList files;
        for (int i = 0; i < selection.count(); i++){
            QModelIndex index = selection.at(i);
            QTableWidgetItem *item = filesTable->item(index.row(),0);
            QString fileName = fileNameOfItem(item);
            qInfo() << index.row() << ":" << fileName;
            files << fileName;
        }
        exportData(files);
    }
#ifndef QT_NO_CLIPBOARD
    else if (action == copyAction)
        QGuiApplication::clipboard()->setText(QDir::toNativeSeparators(fileName));
#endif
}
